package com.ssy.lingxi.member.merchant.serviceimpl.base;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.entity.*;
import com.ssy.lingxi.member.merchant.model.bo.AuthBO;
import com.ssy.lingxi.member.merchant.model.bo.ChannelAuthBO;
import com.ssy.lingxi.member.merchant.model.bo.DataAuthBO;
import com.ssy.lingxi.member.merchant.model.constant.MemberUserAuthTypeEnum;
import com.ssy.lingxi.member.merchant.repository.*;
import com.ssy.lingxi.member.merchant.service.base.IBaseAuthService;
import com.ssy.lingxi.member.merchant.utils.AuthBOUtils;
import com.ssy.lingxi.member.merchant.utils.ChannelAuthUtil;
import com.ssy.lingxi.member.merchant.utils.DataAuthUtil;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * (内部)会员、用户菜单权限、数据权限、渠道权限服务接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2020-09-15
 */
@Service
public class BaseAuthServiceImpl implements IBaseAuthService {
    @Resource
    private MemberAuthRepository memberAuthRepository;

    @Resource
    private MemberRoleAuthConfigRepository memberRoleAuthConfigRepository;

    @Resource
    private MemberUserAuthRepository memberUserAuthRepository;

    @Resource
    private MemberRoleRepository memberRoleRepository;

    @Resource
    private MemberUserRepository memberUserRepository;

    @Resource
    private MemberUserChannelRepository memberUserChannelRepository;

    @Resource
    private MemberRelationRepository relationRepository;

    @Resource
    private MemberRelationAuthRepository relationAuthRepository;

//    /**
//     * 重新构建用户数据权限
//     *
//     * @param member 会员
//     * @return 操作结果
//     */
//    @Transactional(rollbackFor = BusinessException.class)
//    @Override
//    public Wrapper<Void> rebuildMemberUserDataAuth(MemberDO member) {
//        List<MemberRoleDO> roles = memberRoleRepository.findByMemberAndTypeEnum(member, MemberUserAuthTypeEnum.NORMAL.getCode());
//        if(CollectionUtils.isEmpty(roles)) {
//            return Wrapper.success();
//        }
//
//        List<MemberUserDO> users = memberUserRepository.findByMemberAndTypeEnum(member, MemberUserAuthTypeEnum.NORMAL.getCode());
//        if(CollectionUtils.isEmpty(users)) {
//            return Wrapper.success();
//        }
//
//        //循环遍历用户，“重新”构建数据权限
//        //Step 1: 首先构建角色自身的数据权限
//        for (MemberUserDO user : users) {
//            List<DataAuthBO> dataAuthBOList = user.getRoles().stream().filter(role -> !CollectionUtils.isEmpty(role.getAuthConfig())).flatMap(role ->
//                    role.getAuthConfig().stream().map(authConfig -> {
//                        DataAuthBO authBO = new DataAuthBO();
//                        authBO.setUrl(authConfig.getMenu().getUrl());
//                        authBO.setSource(authConfig.getMenu().getSource());
//                        //当前用户Id
//                        authBO.setUserIds(Stream.of(user.getId()).collect(Collectors.toList()));
//                        return authBO;
//                    })
//            ).collect(Collectors.toList());
//            user.getUserAuth().setDataAuth(dataAuthBOList);
//        }
//
//        //Step 2: 合并授权组织机构下用户的数据权限
//        for (MemberUserDO user : users) {
//            List<DataAuthBO> authBOList = user.getUserAuth().getDataAuth();
//            if(CollectionUtils.isEmpty(authBOList)) {
//                continue;
//            }
//
//            List<Long> orgIds = user.getRoles().stream().filter(role -> !CollectionUtils.isEmpty(role.getAuthConfig())).flatMap(role -> role.getAuthConfig().stream()).filter(config -> !CollectionUtils.isEmpty(config.getOrgs())).flatMap(config -> config.getOrgs().stream()).map(MemberOrganizationDO::getId).distinct().collect(Collectors.toList());
//            if(CollectionUtils.isEmpty(orgIds)) {
//                continue;
//            }
//
//            List<MemberUserDO> mergeUsers = users.stream().filter(u -> !u.getId().equals(user.getId())).filter(u -> Objects.nonNull(u.getOrg()) && orgIds.contains(u.getOrg().getId())).collect(Collectors.toList());
//            for (DataAuthBO authBO : authBOList) {
//                authBO.getUserIds().addAll(mergeUsers.stream().filter(u -> u.getUserAuth().getDataAuth().stream().anyMatch(auth -> auth.getSource().equals(authBO.getSource()) && auth.getUrl().equals(authBO.getUrl()))).map(MemberUserDO::getId).collect(Collectors.toList()));
//            }
//        }
//
//        memberUserRepository.saveAll(users);
//        return Wrapper.success();
//    }

    /**
     * 重新构建用户数据权限
     *
     * @param member 会员
     * @return 操作结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> rebuildMemberUserDataAuth(MemberDO member) {
        List<MemberRoleDO> roles = memberRoleRepository.findByMemberAndTypeEnum(member, MemberUserAuthTypeEnum.NORMAL.getCode());
        if(CollectionUtils.isEmpty(roles)) {
            return Wrapper.success();
        }

        List<MemberUserDO> users = memberUserRepository.findByMemberAndTypeEnum(member, MemberUserAuthTypeEnum.NORMAL.getCode());
        if(CollectionUtils.isEmpty(users)) {
            return Wrapper.success();
        }

        //循环遍历用户，“重新”构建数据权限
        //Step 1: 首先构建角色自身的数据权限
        for (MemberUserDO user : users) {
            List<DataAuthBO> dataAuthBOList = user.getRoles().stream().filter(role -> !CollectionUtils.isEmpty(role.getAuthConfig())).flatMap(role ->
                    role.getAuthConfig().stream().map(authConfig -> {
                        DataAuthBO authBO = new DataAuthBO();
                        authBO.setUrl(authConfig.getMenu().getUrl());
                        authBO.setSource(authConfig.getMenu().getSource());
                        //当前用户Id
                        authBO.setUserIds(Stream.of(user.getId()).collect(Collectors.toList()));
                        return authBO;
                    })
            ).collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(DataAuthBO::quickEquals))), ArrayList::new));
            user.getUserAuth().setDataAuth(dataAuthBOList);
        }

        //Step 2: 合并授权组织机构下用户的数据权限(根据菜单url合并)
        for (MemberUserDO user : users) {
            List<DataAuthBO> authBOList = user.getUserAuth().getDataAuth();
            if(CollectionUtils.isEmpty(authBOList)) {
                continue;
            }

            List<MemberRoleAuthConfigDO> memberRoleAuthConfigs = user.getRoles().stream().flatMap(role -> role.getAuthConfig().stream()).collect(Collectors.toList());

            for (DataAuthBO authBO : authBOList) {
                List<Long> orgIds = memberRoleAuthConfigs.stream().filter(memberRoleAuthConfig -> memberRoleAuthConfig.getMenu().getSource().equals(authBO.getSource()) && memberRoleAuthConfig.getMenu().getUrl().equals(authBO.getUrl()) && !CollectionUtils.isEmpty(memberRoleAuthConfig.getOrgs())).flatMap(memberRoleAuthConfig -> memberRoleAuthConfig.getOrgs().stream().map(MemberOrganizationDO::getId)).distinct().collect(Collectors.toList());
                if(CollectionUtils.isEmpty(orgIds)) {
                    continue;
                }

                //合并当前用户所有用户角色配置的组织机构Id
                List<Long> userIds = users.stream().filter(u -> !u.getId().equals(user.getId())).filter(u -> Objects.nonNull(u.getOrg()) && orgIds.contains(u.getOrg().getId())).map(MemberUserDO::getId).distinct().collect(Collectors.toList());
                if(CollectionUtils.isEmpty(userIds)) {
                    continue;
                }

                authBO.getUserIds().addAll(userIds);
            }
        }

        memberUserRepository.saveAll(users);
        return Wrapper.success();
    }

    /**
     * 合并会员权限
     * @param memberDO 会员
     * @return 合并结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> mergeMemberAuthFromRelation(MemberDO memberDO) {
        //合并会员权限
        List<MemberRelationDO> platformRelationList = relationRepository.findBySubMemberIdAndRelType(memberDO.getId(), MemberRelationTypeEnum.PLATFORM.getCode());
        List<List<AuthBO>> allAuthList = platformRelationList.stream().map(p -> p.getRelationAuth().getAuth()).collect(Collectors.toList());
        List<AuthBO> authBOList = AuthBOUtils.mergeAndDistinct(allAuthList);

        MemberAuthDO memberAuthDO = memberDO.getMemberAuth();
        if(memberAuthDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_AUTH_DOES_NOT_EXIST);
        }

        memberAuthDO.setAuth(authBOList);
        memberAuthRepository.saveAndFlush(memberAuthDO);

        //会员下属角色权限
        //不能用Set做循环来修改，要转换为List，否则异常：java.util.ConcurrentModificationException
        List<MemberRoleDO> memberRoles = new ArrayList<>(memberDO.getMemberRoles());
        memberRoles.forEach(memberRoleDO -> {
            //下属管理员角色
            if(memberRoleDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
                memberRoleDO.setAuth(authBOList);
            } else {
                AuthBOUtils.removeInSource(memberRoleDO.getAuth(), authBOList);
            }
        });
        memberRoleRepository.saveAll(memberRoles);

        //会员下属用户权限
        List<MemberUserDO> memberUsers = new ArrayList<>(memberDO.getUsers());
        List<MemberUserAuthDO> userAuthDOList = memberUserAuthRepository.findByUserIn(memberUsers);
        if(CollectionUtils.isEmpty(userAuthDOList)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_AUTH_DOES_NOT_EXIST);
        }

        userAuthDOList.forEach(userAuthDO ->{
            //下属管理员用户
            if(userAuthDO.getUser().getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
                userAuthDO.setAuth(authBOList);
            } else {
                AuthBOUtils.removeInSource(userAuthDO.getAuth(), authBOList);
            }
        });

        memberUserAuthRepository.saveAll(userAuthDOList);

        return Wrapper.success();
    }

    /**
     * 更新会员角色后，更新会员用户的权限
     *
     * @param memberRoleDO 已经更新的会员角色
     * @return 更新结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> updateMemberUserAuthByUpdateMemberRole(MemberRoleDO memberRoleDO) {
        //构建非管理员用户的权限
        List<MemberUserDO> memberUsers = memberRoleDO.getUsers().stream().filter(user -> user.getTypeEnum().equals(MemberUserAuthTypeEnum.NORMAL.getCode())).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(memberUsers)) {
            List<MemberUserAuthDO> userAuthList = new ArrayList<>();
            memberUsers.forEach(memberUserDO -> {
                List<AuthBO> rolesAuthList = AuthBOUtils.mergeAndDistinct(memberUserDO.getRoles().stream().map(MemberRoleDO::getAuth).collect(Collectors.toList()));
                MemberUserAuthDO userAuthDO = memberUserDO.getUserAuth();
                userAuthDO.setAuth(rolesAuthList);
                userAuthList.add(userAuthDO);
            });

            memberUserAuthRepository.saveAll(userAuthList);
        }

        return Wrapper.success();
    }

    /**
     * 修改角色权限后，修改平台会员权限
     *
     * @param roleDO    角色
     * @return 更新结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> rebuildMemberAuthByUpdateRoleAuth(RoleDO roleDO) {
        //Step 1: 修改平台会员关系的权限
        Specification<MemberRelationDO> specification = (Specification<MemberRelationDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()));
            list.add(criteriaBuilder.equal(root.get("subRoleId").as(Long.class), roleDO.getId()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        List<MemberRelationDO> relationDOList = relationRepository.findAll(specification);

        if(CollectionUtils.isEmpty(relationDOList)) {
            return Wrapper.success();
        }

        List<MemberRelationAuthDO> relationAuthList = relationAuthRepository.findByRelationIn(relationDOList);
        relationAuthList.forEach(relationAuth -> relationAuth.setAuth(roleDO.getRoleAuth().getAuth()));
        relationAuthRepository.saveAll(relationAuthList);

        //会员权限
        List<MemberDO> memberDOList = new ArrayList<>(roleDO.getMembers());
        List<MemberAuthDO> memberAuthList = new ArrayList<>();
        for(MemberDO memberDO : memberDOList) {
            //合并会员所有角色的权限作为会员权限
            MemberAuthDO memberAuth = memberDO.getMemberAuth();
            memberAuth.setAuth(AuthBOUtils.distinct(memberDO.getRoles().stream().flatMap(role -> role.getRoleAuth().getAuth().stream()).collect(Collectors.toList())));
            memberAuthList.add(memberAuth);

            //会员下属角色权限
            List<MemberRoleDO> memberRoles = new ArrayList<>(memberDO.getMemberRoles());
            //下属管理员角色
            MemberRoleDO memberAdminRoleDO = memberRoles.stream().filter(memberRoleDO -> memberRoleDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())).findFirst().orElse(null);
            if(memberAdminRoleDO != null && AuthBOUtils.listNotEqual(memberAdminRoleDO.getAuth(), memberAuth.getAuth())) {
                memberAdminRoleDO.setAuth(memberAuth.getAuth());
                memberRoleRepository.saveAndFlush(memberAdminRoleDO);
            }

            //其他自定义角色
            List<MemberRoleDO> memberNormalRoleDOList = memberRoles.stream().filter(memberRoleDO -> !memberRoleDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())).collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(memberNormalRoleDOList)) {
                memberNormalRoleDOList.forEach(memberRoleDO -> AuthBOUtils.removeInSource(memberRoleDO.getAuth(), memberAuth.getAuth()));
                memberRoleRepository.saveAll(memberNormalRoleDOList);
            }

            //会员下属用户权限
            List<MemberUserDO> memberUsers = new ArrayList<>(memberDO.getUsers());
            //下属管理员用户
            MemberUserAuthDO memberAdminUserAuth = memberUsers.stream().filter(memberUserDO -> memberUserDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())).map(MemberUserDO::getUserAuth).findFirst().orElse(null);
            if(memberAdminUserAuth != null) {
                memberAdminUserAuth.setAuth(memberAuth.getAuth());
                memberUserAuthRepository.saveAndFlush(memberAdminUserAuth);
            }

            List<MemberUserAuthDO> memberNormalUserAuthorities = memberUsers.stream().filter(memberUserDO -> !memberUserDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())).map(MemberUserDO::getUserAuth).collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(memberNormalUserAuthorities)) {
                memberNormalUserAuthorities.forEach(memberUserAuth -> AuthBOUtils.removeInSource(memberUserAuth.getAuth(), memberAuth.getAuth()));
                memberUserAuthRepository.saveAll(memberNormalUserAuthorities);
            }
        }

        memberAuthRepository.saveAll(memberAuthList);
        return Wrapper.success();
    }

    /**
     * 修改角色权限后，去掉会员、会员用户的权限中已经被去掉的权限
     *
     * @param roleDO 角色
     * @return 更新结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> updateMemberAuthByUpdateRoleAuth(RoleDO roleDO) {
        List<AuthBO> authBOList = roleDO.getRoleAuth().getAuth();

        //Step 1:移除平台会员关系的权限
        Specification<MemberRelationDO> specification = (Specification<MemberRelationDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()));
            list.add(criteriaBuilder.equal(root.get("subRoleId").as(Long.class), roleDO.getId()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        List<MemberRelationDO> relationDOList = relationRepository.findAll(specification);

        if(CollectionUtils.isEmpty(relationDOList)) {
            return Wrapper.success();
        }

        List<MemberRelationAuthDO> relationAuthList = relationAuthRepository.findByRelationIn(relationDOList);

        relationAuthList.forEach(relationAuth -> AuthBOUtils.removeInSource(relationAuth.getAuth(), authBOList));
        relationAuthRepository.saveAll(relationAuthList);


        //会员权限
        List<MemberDO> memberDOList = new ArrayList<>(roleDO.getMembers());
        List<MemberAuthDO> memberAuthList = new ArrayList<>();
        for(MemberDO memberDO : memberDOList) {
            MemberAuthDO memberAuth = memberDO.getMemberAuth();
            List<List<AuthBO>> allMemberAuthList = memberDO.getRoles().stream().map(role -> role.getRoleAuth().getAuth()).collect(Collectors.toList());
            AuthBOUtils.removeFromSource(memberAuth.getAuth(), authBOList, allMemberAuthList);
            memberAuthList.add(memberAuth);

            //会员下属角色权限
            List<MemberRoleDO> memberRoles = new ArrayList<>(memberDO.getMemberRoles());
            //下属管理员角色
            MemberRoleDO memberAdminRoleDO = memberRoles.stream().filter(memberRoleDO -> memberRoleDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())).findFirst().orElse(null);
            if(memberAdminRoleDO != null && AuthBOUtils.listNotEqual(memberAdminRoleDO.getAuth(), memberAuth.getAuth())) {
                memberAdminRoleDO.setAuth(memberAuth.getAuth());
                memberRoleRepository.saveAndFlush(memberAdminRoleDO);
            }

            //其他自定义角色
            List<MemberRoleDO> memberNormalRoleDOList = memberRoles.stream().filter(memberRoleDO -> !memberRoleDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())).collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(memberNormalRoleDOList)) {
                memberNormalRoleDOList.forEach(memberRoleDO -> AuthBOUtils.removeInSource(memberRoleDO.getAuth(), memberAuth.getAuth()));
                memberRoleRepository.saveAll(memberNormalRoleDOList);
            }

            //会员下属用户权限
            List<MemberUserDO> memberUsers = new ArrayList<>(memberDO.getUsers());
            //下属管理员用户
            MemberUserAuthDO memberAdminUserAuth = memberUsers.stream().filter(memberUserDO -> memberUserDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())).map(MemberUserDO::getUserAuth).findFirst().orElse(null);
            if(memberAdminUserAuth != null) {
                memberAdminUserAuth.setAuth(memberAuth.getAuth());
                memberUserAuthRepository.saveAndFlush(memberAdminUserAuth);
            }

            List<MemberUserAuthDO> memberNormalUserAuthorities = memberUsers.stream().filter(memberUserDO -> !memberUserDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())).map(MemberUserDO::getUserAuth).collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(memberNormalUserAuthorities)) {
                memberNormalUserAuthorities.forEach(memberUserAuth -> AuthBOUtils.removeInSource(memberUserAuth.getAuth(), memberAuth.getAuth()));
                memberUserAuthRepository.saveAll(memberNormalUserAuthorities);
            }
        }

        memberAuthRepository.saveAll(memberAuthList);
        return Wrapper.success();
    }

    /**
     * 修改用户角色的数据权限后，重新构建角色相关会员所有用户的数据权限
     *
     * @param memberDO     会员
     * @param memberRoleDO 会员角色
     * @param orgList      会员组织机构列表
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public void rebuildMemberRoleDataAuth(MemberDO memberDO, MemberRoleDO memberRoleDO, List<MemberOrganizationDO> orgList) {
        //用户角色的数据权限被修改后，需要重构数据权限（被影响的）用户
        List<MemberUserDO> updateUserList = new ArrayList<>(memberRoleDO.getUsers()).stream().filter(userDO -> userDO.getRoles().stream().noneMatch(role -> role.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode()))).collect(Collectors.toList());

        //如果没有普通用户被修改数据权限，返回
        if(CollectionUtils.isEmpty(updateUserList)) {
            return;
        }

        //所有用户
        List<MemberUserDO> userList = new ArrayList<>(memberDO.getUsers());
        List<MemberUserAuthDO> userAuthList = new ArrayList<>();
        updateUserList.forEach(updateUser -> {
            List<DataAuthBO> authBOList = updateUser.getRoles().stream().filter(role -> !CollectionUtils.isEmpty(role.getAuthConfig())).flatMap(role ->
                    role.getAuthConfig().stream().map(authConfig -> {
                        DataAuthBO authBO = new DataAuthBO();
                        authBO.setUrl(authConfig.getMenu().getUrl());
                        authBO.setSource(authConfig.getMenu().getSource());
                        //用户Id
                        List<Long> userIds = Stream.of(updateUser.getId()).collect(Collectors.toList());
                        userIds.addAll(authConfig.getOrgs().stream().flatMap(org -> findOrgAndSubOrgUserIds(org.getId(), userList, orgList).stream()).collect(Collectors.toList()));
                        authBO.setUserIds(userIds.stream().distinct().sorted().collect(Collectors.toList()));
                        return authBO;
                    })
            ).collect(Collectors.toList());
            MemberUserAuthDO userAuth = updateUser.getUserAuth();
            userAuth.setDataAuth(DataAuthUtil.mergeAndDistinct(authBOList));
            userAuthList.add(userAuth);
        });

        memberUserAuthRepository.saveAll(userAuthList);
    }

    /**
     * 新增或修改业务员渠道权限后，根据组织机构层级，从下往上构建所有用户的渠道权限
     * <p>从业务员所在组织往上查找，每个上级子节点的用户合并其直接子节点所有用户的权限</p>
     * @param memberUserDO 渠道权限发生变化的业务员
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public void rebuildUserChannelAuth(MemberUserDO memberUserDO) {
        List<MemberUserDO> userList = new ArrayList<>(memberUserDO.getMember().getUsers()).stream().filter(user -> user.getTypeEnum().equals(MemberUserAuthTypeEnum.NORMAL.getCode())).collect(Collectors.toList());
        List<MemberOrganizationDO> orgList = new ArrayList<>(memberUserDO.getMember().getOrgs());

        List<MemberUserAuthDO> updateUserAuthList = new ArrayList<>();
        recurseFindUpperOrgUsers(memberUserDO.getOrg().getParentId(), memberUserDO.getUserAuth().getChannelAuth(), updateUserAuthList, userList, orgList);

        memberUserAuthRepository.saveAll(updateUserAuthList);
    }

    /**
     * 新增或修改用户时，当用户组织机构发生变化时，重新构建该用户的渠道权限
     * <p>用于MemberAbilityUserServiceImpl</p>
     * @param memberUserDO 当前用户
     * @param needSaveAndFlush 是否保存（新增用户时需要保存，修改用户时不需要保存）
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public void rebuildUserDataAndChannelAuth(MemberUserDO memberUserDO, boolean needSaveAndFlush) {
        //超级管理员用户有所有权限，不需要设置
        if(memberUserDO.getRoles().stream().anyMatch(role -> role.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode()))) {
            memberUserDO.getUserAuth().setDataAuth(new ArrayList<>());
            memberUserDO.getUserAuth().setChannelAuth(new ArrayList<>());
            return;
        }

        boolean needUpdate = false;

        @SuppressWarnings("unchecked")
        final List<MemberUserDO>[] userList = new List[]{new ArrayList<>()};

        @SuppressWarnings("unchecked")
        final List<MemberOrganizationDO>[] orgList = new List[]{new ArrayList<>()};

        //数据权限
        List<MemberRoleAuthConfigDO> authConfigDOList = memberUserDO.getRoles().stream().flatMap(role ->  role.getAuthConfig().stream()).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(authConfigDOList)) {
            needUpdate = true;
            List<DataAuthBO> authBOList = authConfigDOList.stream().map(authConfig -> {
                DataAuthBO authBO = new DataAuthBO();
                authBO.setUrl(authConfig.getMenu().getUrl());
                authBO.setSource(authConfig.getMenu().getSource());
                List<Long> subOrgUserIds = Stream.of(memberUserDO.getId()).collect(Collectors.toList());
                if(!CollectionUtils.isEmpty(authConfig.getOrgs())) {
                    if(CollectionUtils.isEmpty(userList[0])) {
                        userList[0] = new ArrayList<>(memberUserDO.getMember().getUsers());
                    }

                    if(CollectionUtils.isEmpty(orgList[0])) {
                        orgList[0] = new ArrayList<>(memberUserDO.getMember().getOrgs());
                    }

                    subOrgUserIds.addAll(authConfig.getOrgs().stream().flatMap(org -> findOrgAndSubOrgUserIds(org.getId(), userList[0], orgList[0]).stream()).collect(Collectors.toList()));
                }
                authBO.setUserIds(subOrgUserIds.stream().distinct().collect(Collectors.toList()));
                return authBO;
            }).collect(Collectors.toList());
            memberUserDO.getUserAuth().setDataAuth(DataAuthUtil.mergeAndDistinct(authBOList));
        }

        //渠道权限
        if(memberUserChannelRepository.existsByMemberId(memberUserDO.getMember().getId())) {
            if(CollectionUtils.isEmpty(orgList[0])) {
                orgList[0] = new ArrayList<>(memberUserDO.getMember().getOrgs());
            }

            List<Long> subOrgIds = new ArrayList<>();
            recurseFindSubOrgIds(memberUserDO.getOrg().getId(), subOrgIds, orgList[0]);
            if(!CollectionUtils.isEmpty(subOrgIds)) {
                if(CollectionUtils.isEmpty(userList[0])) {
                    userList[0] = new ArrayList<>(memberUserDO.getMember().getUsers());
                }

                List<MemberUserDO> salesList = userList[0].stream().filter(user -> user.getIsSales() != null && user.getIsSales().equals(EnableDisableStatus.ENABLE.getCode()) && subOrgIds.contains(user.getOrg().getId())).collect(Collectors.toList());
                if(!CollectionUtils.isEmpty(salesList)) {
                    needUpdate = true;
                    memberUserDO.getUserAuth().setChannelAuth(salesList.stream().flatMap(sales -> sales.getUserAuth().getChannelAuth().stream()).distinct().collect(Collectors.toList()));
                }
            }
        }

        if(needUpdate && needSaveAndFlush) {
            memberUserRepository.saveAndFlush(memberUserDO);
        }
    }


    /**
     * 根据组织机构的层级，递归查找所有上级部门的用户
     * @param parentOrgId 当前组织机构的Id
     * @param salesChannelAuthList 渠道权限变更后的业务员的渠道权限
     * @param updateUserAuthList 递归结果：更新渠道权限后的用户权限列表
     * @param userList 所有的非超管用户
     * @param orgList 组织机构列表
     */
    private void recurseFindUpperOrgUsers(Long parentOrgId, List<ChannelAuthBO> salesChannelAuthList, List<MemberUserAuthDO> updateUserAuthList, List<MemberUserDO> userList,  List<MemberOrganizationDO> orgList) {
        if(parentOrgId == null || parentOrgId.equals(0L)) {
            return;
        }

        //由于List是引用类型，所以这里必须要复制一份List<ChannelAuthBO>
        //否则会修改传入的业务员的渠道权限
        List<ChannelAuthBO> authBOList = ChannelAuthUtil.copy(salesChannelAuthList);

        MemberOrganizationDO upperOrg = orgList.stream().filter(org -> org.getId().equals(parentOrgId)).findFirst().orElse(null);
        if(upperOrg == null) {
            return;
        }

        List<MemberUserDO> upperOrgUsers = userList.stream().filter(user -> user.getOrg().getId().equals(upperOrg.getId())).collect(Collectors.toList());

        List<Long> subOrgIds =  orgList.stream().filter(org -> org.getParentId().equals(upperOrg.getId())).map(MemberOrganizationDO::getId).collect(Collectors.toList());
        List<MemberUserDO> subOrgUsers = userList.stream().filter(user -> subOrgIds.contains(user.getOrg().getId())).collect(Collectors.toList());
        //ChannelAuthBO必须定义equals()方法
        List<ChannelAuthBO> subOrgChannelAuthList = subOrgUsers.stream().flatMap(user -> user.getUserAuth().getChannelAuth().stream()).collect(Collectors.toList());
        authBOList.addAll(subOrgChannelAuthList);
        authBOList = authBOList.stream().distinct().collect(Collectors.toList());

        List<ChannelAuthBO> finalAuthBOList = authBOList;
        upperOrgUsers.forEach(user -> {
            if(user.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
                user.getUserAuth().setDataAuth(new ArrayList<>());
                user.getUserAuth().setChannelAuth(new ArrayList<>());
            } else {
                user.getUserAuth().setChannelAuth(finalAuthBOList);
            }
        });

        updateUserAuthList.addAll(upperOrgUsers.stream().map(MemberUserDO::getUserAuth).collect(Collectors.toList()));

        recurseFindUpperOrgUsers(upperOrg.getParentId(), finalAuthBOList, updateUserAuthList, userList, orgList);
    }


    /**
     * 查找当前、以及所有下级组织机构所有用户的Id列表
     * @param orgId    当前组织机构的Id
     * @param userList  所有用户列表
     * @param orgList  所有组织机构列表
     */
    private List<Long> findOrgAndSubOrgUserIds(Long orgId, List<MemberUserDO> userList, List<MemberOrganizationDO> orgList) {
        List<Long> subOrgIds = new ArrayList<>();
        recurseFindSubOrgIds(orgId, subOrgIds, orgList);
        //加上当前组织机构的Id
        subOrgIds.add(orgId);
        return userList.stream().filter(user -> !Objects.isNull(user.getOrg()) && subOrgIds.contains(user.getOrg().getId())).map(MemberUserDO::getId).collect(Collectors.toList());
    }

    /**
     * 根据组织机构的层级，递归查找所有下级组织机构的Id列表
     * @param topOrgId 当前的组织机构Id
     * @param subOrgIds 下级组织机构Id列表
     * @param orgList  所有的组织机构
     */
    private void recurseFindSubOrgIds(Long topOrgId,  List<Long> subOrgIds, List<MemberOrganizationDO> orgList) {
        if(topOrgId == null) {
            return;
        }

        List<MemberOrganizationDO> subOrgList = orgList.stream().filter(org -> org.getParentId().equals(topOrgId)).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(subOrgList)) {
            return;
        }

        subOrgIds.addAll(subOrgList.stream().map(MemberOrganizationDO::getId).collect(Collectors.toList()));

        subOrgList.forEach(subOrg -> recurseFindSubOrgIds(subOrg.getId(), subOrgIds, orgList));
    }
}
